// -*- mode:c++ -*-
//
// 2009-2010 HIT Microelectronic Center all rights reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Date: Dec. 2009
// Authors: Gou Pengfei

decode BLOCKSTATUS default Unknown::unknown() {

0x1: decode OPCODE default Unknown::unknown() {
    format COp {
        0x0: nop        ({{ }}, IsNop);
        0x1: gens       ({{RESULT.sd = sext<16>(CONSTANT);}},IsConst);
        0x2: genu   ({{RESULT.ud = CONSTANT;}},IsConst);
        0x4: app        ({{RESULT.ud = (Op0.ud << 16) | CONSTANT;}},IsConst);
    }
    
     format M3Op {
        0x6: m3 ({{RESULT.ud = Op0.ud;}}, IsMove);
    }   

    format M4Op {
        0x7: m4 ({{RESULT.ud = Op0.ud;}},  IsMove);
    }
    
    format BwithOffset {
        0x8: bro        ({{NextBlockPC = xc->getBlockPC() + (sext<20>(BRANCH_OFFSET) << 7);}});
        0x9: callo      ({{NextBlockPC = xc->getBlockPC() + (sext<20>(BRANCH_OFFSET) << 7);}}, IsCall);
    }


    
    format syscall {
    0xa: scall      ({{xc->setFault(NoFault);}}, IsSyscall); // Set fault as NoFault because syscall will be handled in execute stage , not in this inst 
    }
    
    format BwithoutOffset{
        0xc: br     ({{NextBlockPC = Op0.ud;}});
        0xd: call       ({{NextBlockPC = Op0.ud;}}, IsCall);
        0xe: ret        ({{NextBlockPC = Op0.ud;}}, IsReturn);
    }
    
    0x10: decode XOPCODE {
            format GOp {
                    0x0:    nullify     ({{
                        xc->setDataflowTokenType( TheISA::Nullification );
                        xc->setIntResult(0); // Set it for consistency
                    }},IsNullify);
            }
    }
    
    0x12: decode XOPCODE {
            format GOp {
                    0x0:    fitod   ({{FRESULT.df = static_cast<double>(Op0.sd);}});
                    0x1:    fdtoi   ({{RESULT.sd = static_cast<int64_t>(FOp0.df);}});
                    0x2:    fstod   ({{FRESULT.df = static_cast<double>(FOp0.sf);}});
                    0x3:    fdtos   ({{FRESULT.sf = static_cast<float>(FOp0.df);}});
            }
    }
    
    0x13: decode XOPCODE {
            format GOp {
                    0x0:    mov     ({{RESULT.ud = Op0.ud;}},IsMove);
                    0x1:    extsb   ({{RESULT.sd = sext<8>(bits(Op0.ud,7, 0));}});
                    0x2:    extsh   ({{RESULT.sd = sext<16>(bits(Op0.ud, 15, 0));}});
                    0x3:    extsw   ({{RESULT.sd = sext<32>(bits(Op0.ud, 31, 0));}});
                    0x4:    extub   ({{RESULT.ud = bits(Op0.ud, 7, 0);}});
                    0x5:    extuh   ({{RESULT.ud = bits(Op0.ud, 15, 0);}});
                    0x6:    extuw   ({{RESULT.ud = bits(Op0.ud, 31, 0);}});
            }
    }
    
    0x16: decode XOPCODE {
            format GOp {
                    0x0:    fadd    ({{FRESULT.df = FOp0.df + FOp1.df;}});
                    0x1:    fsub    ({{FRESULT.df = FOp0.df - FOp1.df;}});
                    0x2:    fmul    ({{FRESULT.df = FOp0.df * FOp1.df;}}, FloatMultOp);
                    0x3:    fdiv    ({{
                                                                 double temp = FOp1.df;
                                                                 if ( temp == 0 ){
                                                                     //warn("Dividing zero.\n");
                                                                     FRESULT.df = 0;
                                                                 } else {
                                                                     FRESULT.df = FOp0.df / temp;
                                                                 }
                                                                 }}, FloatDivOp);
                    0x4:    feq     ({{RESULT.ud = (FOp0.df == FOp1.df) ? 1 : 0;}},IsTest);
                    0x5:    fle     ({{RESULT.ud = (FOp0.df <= FOp1.df) ? 1 : 0;}},IsTest);
                    0x6:    flt     ({{RESULT.ud = (FOp0.df < FOp1.df) ? 1 : 0;}},IsTest);
                    0x7:    fne     ({{RESULT.ud = (FOp0.df != FOp1.df) ? 1 : 0;}},IsTest);
                    0x8:    fgt     ({{RESULT.ud = (FOp0.df > FOp1.df) ? 1: 0;}},IsTest);      
                    0x9:    fge     ({{RESULT.ud = (FOp0.df >= FOp1.df) ? 1 : 0;}},IsTest);
            }
    }
    
    0x17: decode XOPCODE {
            format GOp {
                0x0:    add     ({{RESULT.ud = Op0.ud + Op1.ud;}});
                0x1:    sub     ({{RESULT.ud = Op0.ud - Op1.ud;}});
                0x2:    mul     ({{RESULT.ud = Op0.ud * Op1.ud;}}, IntMultOp);
                0x3:    divs    ({{
                                                                  int64_t temp = Op1.sd;
                                                                                 if ( temp == 0 ){
                                                                                     //warn("Dividing zero.\n");
                                                                                     RESULT.sd = 0;
                                                                                 } else {
                                                                         RESULT.sd = Op0.sd / temp;
                                                                     }
                                                        }}, IntDivOp);
                0x4:    divu    ({{
                                                 uint64_t temp = Op1.ud;
                                                                                 if ( temp == 0 ){
                                                                                     //warn("Dividing zero.\n");
                                                                                     RESULT.ud = 0;
                                                                                 } else {
                                                                         RESULT.ud = Op0.ud / temp;
                                                                     }                                                   
                                                        }}, IntDivOp);
                
                0x8:    and ({{RESULT.ud = Op0.ud & Op1.ud;}});
                0x9:    or      ({{RESULT.ud = Op0.ud | Op1.ud;}});
                0xa:    xor     ({{RESULT.ud = Op0.ud ^ Op1.ud;}});

                0xc:    sll     ({{RESULT.ud = Op0.ud << ((Op1.ud)&0x3f);}});
                0xd:    srl     ({{RESULT.ud = Op0.ud >> ((Op1.ud)&0x3f);}});
                0xe:    sra     ({{RESULT.sd = Op0.sd >> ((Op1.ud)&0x3f);}});  // Is this safe enough? Maybe we should take a more safe sign handling method

                0x10: teq     ({{RESULT.ud = (Op0.ud == Op1.ud) ? 1 : 0;}},IsTest);
                0x11: tle       ({{RESULT.ud = (Op0.sd <= Op1.sd) ? 1 : 0;}},IsTest);
                0x12: tlt       ({{RESULT.ud = (Op0.sd < Op1.sd) ? 1 : 0;}},IsTest);
                0x13: tleu  ({{RESULT.ud = (Op0.ud <= Op1.ud) ? 1 : 0;}},IsTest);
                0x14: tltu  ({{RESULT.ud = (Op0.ud < Op1.ud) ? 1 : 0;}},IsTest);
                0x15: tne       ({{RESULT.ud = (Op0.ud != Op1.ud) ? 1 : 0;}},IsTest);
                0x16: tgt       ({{RESULT.ud = (Op0.sd > Op1.sd) ? 1 : 0;}},IsTest);
                0x17: tge       ({{RESULT.ud = (Op0.sd >= Op1.sd) ? 1 : 0;}},IsTest);
                0x18: tgtu  ({{RESULT.ud = (Op0.ud > Op1.ud) ? 1 : 0;}},IsTest);
                0x19: tgeu  ({{RESULT.ud = (Op0.ud >= Op1.ud) ? 1 : 0;}},IsTest);          
                
                }
    }
    
    0x18: decode XOPCODE {
            format IOp {
                    0x0:    movi    ({{RESULT.sd = sext<9>(IMM);}},IsMove);
                    0x1:    mfpc    ({{RESULT.ud = xc->readPC();}});
            }
    }
    
    0x1f: decode XOPCODE {
            format IOp {
                0x0:    addi    ({{RESULT.ud = Op0.ud + sext<9>(IMM);}});
                0x1:    subi    ({{RESULT.ud = Op0.ud - sext<9>(IMM);}});
                0x2:    muli    ({{RESULT.ud = Op0.ud * sext<9>(IMM);}}, IntMultOp);
                0x3:    divsi   ({{
                                                         int64_t temp = sext<9>(IMM);
                                                         if ( temp == 0 ){
                                                             //warn("Dividing zero.\n");
                                                             RESULT.sd = 0;
                                                         }else{
                                                             RESULT.sd = Op0.sd / temp;
                                                         }
                                                     }}, IntDivOp);
                0x4:    divui   ({{
                                                         uint64_t temp = static_cast<uint64_t>(sext<9>(IMM));
                                                         if ( temp == 0 ){
                                                             //warn("Dividing zero.\n");
                                                             RESULT.ud = 0;
                                                         }else{
                                                             RESULT.ud = Op0.ud / temp;
                                                         }
                                                      }}, IntDivOp);
                
                0x8:    andi    ({{RESULT.ud = Op0.ud & sext<9>(IMM);}});
                0x9:    ori     ({{RESULT.ud = Op0.ud | sext<9>(IMM);}});
                0xa:    xori        ({{RESULT.ud = Op0.ud ^ sext<9>(IMM);}});

                0xc:    slli        ({{RESULT.ud = Op0.ud << ((sext<9>(IMM))&0x3f);}});
                0xd:    srli        ({{RESULT.ud = Op0.ud >> ((sext<9>(IMM))&0x3f);}});
                0xe:    srai    ({{RESULT.sd = Op0.sd >> ((sext<9>(IMM))&0x3f);}});  // Is this safe enough? Maybe we should take a more safe sign handling method

                0x10:   teqi    ({{RESULT.ud = (Op0.sd == sext<9>(IMM)) ? 1 : 0;}},IsTest);
                0x11: tlei      ({{RESULT.ud = (Op0.sd <= sext<9>(IMM)) ? 1 : 0;}},IsTest);
                0x12: tlti      ({{RESULT.ud = (Op0.sd < sext<9>(IMM)) ? 1 : 0;}},IsTest);
                0x13: tleui ({{RESULT.ud = (Op0.ud <=  static_cast<uint64_t>(sext<9>(IMM))) ? 1 : 0;}},IsTest);
                0x14: tltui ({{RESULT.ud = (Op0.ud < static_cast<uint64_t>(sext<9>(IMM))) ? 1 : 0;}},IsTest);
                0x15: tnei  ({{RESULT.ud = (Op0.ud != sext<9>(IMM)) ? 1 : 0;}},IsTest);
                0x16: tgti      ({{RESULT.ud = (Op0.sd > sext<9>(IMM)) ? 1 : 0;}},IsTest);
                0x17: tgei  ({{RESULT.ud = (Op0.sd >= sext<9>(IMM)) ? 1 : 0;}},IsTest);
                0x18: tgtui ({{RESULT.ud = (Op0.ud > static_cast<uint64_t>(sext<9>(IMM))) ? 1 : 0;}},IsTest);
                0x19: tgeui ({{RESULT.ud = (Op0.ud >=  static_cast<uint64_t>(sext<9>(IMM))) ? 1 : 0;}},IsTest);
                
                }
    }
    
 format  LoadMemory {
    0x20: lb        ({{RESULT.ub = Mem.ub;}}, mem_flags=NO_ALIGN_FAULT);
    0x21:   lh      ({{RESULT.uh = Mem.uh;}}, mem_flags=NO_HALF_WORD_ALIGN_FAULT );
    0x22: lw        ({{RESULT.uw = Mem.uw;}});
    0x23:   ld      ({{RESULT.ud = Mem.ud;}});
    0x24:   lbs     ({{RESULT.sb = Mem.sb;}}, mem_flags=NO_ALIGN_FAULT);
    0x25:   lhs     ({{RESULT.sh = Mem.sh;}}, mem_flags=NO_HALF_WORD_ALIGN_FAULT);
    0x26:   lws     ({{RESULT.sw = Mem.sw;}});
    0x27:   lock    ({{RESULT.ud = Mem.ub;}}, mem_flags=LLSC); 
 }
 
 format StoreMemory {
    0x28:   sb      ({{Mem.ub = Op1.ub;}}, mem_flags=NO_ALIGN_FAULT);
    0x29:   sh      ({{Mem.uh = Op1.uh;}}, mem_flags=NO_HALF_WORD_ALIGN_FAULT);
    0x2a:   sw      ({{Mem.uw = Op1.uw;}});
    0x2b:   sd      ({{Mem.ud = Op1.ud;}});
 }
    
}

format HeaderRead {
0x2:readreg ({{
        RESULT.ud = Gr_r.ud;
    }},IsRead,IsGRegWR);
}

format HeaderWrite {
0x3:writereg ({{
        Gr_w.ud = Op0.ud;
    }},IsWrite,IsGRegWR);
}

}

